package com.laomuji.android.mvvm.utils

import androidx.core.widget.NestedScrollView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout

/**
 * 帮助快速实现分页功能
 * 使用NestedScrollView可以兼容滑动冲突,但RecyclerView必须放在NestedScrollView的最下方
 * 需要注意,SwipeRefreshLayout必须放在NestedScrollView外层,防止滑动事件被覆盖
 * @author laomuji666
 * @since 2024/2/21
 */
class PageListUtil(rv: RecyclerView, nsv: NestedScrollView?, private val srl: SwipeRefreshLayout?, private val callback:LoadData) {
    interface LoadData{
        /**
         * 必须实现的加载列表的数据逻辑
         * 在这个函数的开头位置:
         * 在refresh为true时,需要重置计数器.
         * 在refresh为false时,需要计数器+1.
         * 如果没有下一页的数据,需要调用disableLoadMore
         */
        fun loadData(refresh:Boolean)
    }

    //是否正在刷新
    private var isRefresh = false
    //是否正在加载更多
    private var isLoadMore = false
    //是否还有下一页
    private var hasNextPage = false

    init {
        //下拉刷新
        srl?.setOnRefreshListener {
            loadData(true)
        }

        //上拉加载
        if(nsv==null){
            //使用RecyclerView的滑动监听事件
            rv.addOnScrollListener(object : RecyclerView.OnScrollListener() {
                override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                    val linearLayoutManager = recyclerView.layoutManager as LinearLayoutManager?
                    if (linearLayoutManager == null || isRefresh || isLoadMore) {
                        return
                    }
                    val lastPosition = linearLayoutManager.itemCount - 1
                    val lastVisiblePosition = linearLayoutManager.findLastVisibleItemPosition()
                    //当最后一个数据是可见的数据时,加载数据
                    if (lastPosition == lastVisiblePosition) {
                        loadData(false)
                    }
                }
            })
        }else{
            //使用NestedScrollView的滑动事件,兼容滑动冲突
            nsv.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { v, _, scrollY, _, oldScrollY ->
                if(isRefresh||isLoadMore){
                    return@OnScrollChangeListener
                }
                //在item可见并且不完全可见时,并且滑动方向是往下,可以认为是从下往上滑动
                if((scrollY>=(rv.measuredHeight - v.measuredHeight)) && scrollY > oldScrollY){
                    loadData(false)
                }
            })
        }
    }

    /**
     * 加载数据
     * @param refresh 是否刷新
     */
    fun loadData(refresh:Boolean){
        if(refresh){
            isRefresh = true
            hasNextPage = true
        }else{
            isLoadMore = true
        }
        if(!hasNextPage){
            return
        }
        callback.loadData(refresh)
    }

    /**
     * 加载成功,需要在获取到列表数据后调用
     * 只有调用该函数后,才会进入下一次的加载
     */
    fun loadDataSuccess(){
        srl?.isRefreshing = false
        isRefresh = false
        isLoadMore = false
    }

    /**
     * 关闭加载更多
     * 调用该函数后不会在调用加载事件
     */
    fun disableLoadMore(){
        hasNextPage = false
    }
}